package com.example.controller;

import java.util.List;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.example.dto.ApiResponse;
import com.example.dto.BatchRegisterRequest;
import com.example.dto.BatchUpdateRoleRequest;
import com.example.dto.ChangePasswordRequest;
import com.example.dto.MessageResponse;
import com.example.dto.UpdateRoleRequest;
import com.example.dto.UpdateUserRequest;
import com.example.dto.UserDTO;
import com.example.entity.User;
import com.example.service.UserService;
import com.fasterxml.jackson.databind.ObjectMapper;

import jakarta.validation.Valid;

@RestController
@RequestMapping("/api/users")
public class UserController {
    
    private static final Logger logger = LoggerFactory.getLogger(UserController.class);

    @Autowired
    private UserService userService;
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Autowired
    private ObjectMapper objectMapper;

    /**
     * 获取所有用户（仅管理员和教师可以查看）
     * 返回包含角色信息的用户列表
     */
    @GetMapping
    @PreAuthorize("hasRole('ADMIN') or hasRole('TEACHER')")
    public ApiResponse<List<UserDTO>> getAllUsers() {
        return ApiResponse.success("Users retrieved successfully", userService.getAllUsersWithRoles());
    }

    /**
     * 获取指定用户信息（教师可以查看所有学生，学生只能查看自己）
     * 优先从Redis缓存获取，提高查询性能
     */
    @GetMapping("/{id}")
    @PreAuthorize("hasRole('ADMIN') or hasRole('TEACHER') or authentication.principal.id == #id")
    public ApiResponse<UserDTO> getUserById(@PathVariable Long id) {
        try {
            // 1. 先尝试从Redis缓存获取用户信息
            UserDTO cachedUser = getCachedUserById(id);
            if (cachedUser != null) {
                logger.debug("用户信息从Redis缓存获取: userId={}", id);
                return ApiResponse.success("User retrieved successfully", cachedUser);
            }
            
            // 2. 缓存未命中，从数据库查询
            UserDTO user = userService.getUserWithRolesById(id);
            if (user != null) {
                // 3. 将查询结果缓存到Redis
                cacheUserDTO(user);
                logger.debug("用户信息已缓存到Redis: userId={}", id);
                return ApiResponse.success("User retrieved successfully", user);
            }
            return ApiResponse.error("User not found");
            
        } catch (Exception e) {
            logger.warn("获取用户信息时Redis操作失败，降级到数据库查询: {}", e.getMessage());
            UserDTO user = userService.getUserWithRolesById(id);
            if (user != null) {
                return ApiResponse.success("User retrieved successfully", user);
            }
            return ApiResponse.error("User not found");
        }
    }

    /**
     * 更新用户信息（只有管理员或用户自己可以修改）
     * 更新后清除Redis缓存
     */
    @PutMapping("/{id}")
    @PreAuthorize("hasRole('ADMIN') or authentication.principal.id == #id")
    public ApiResponse<?> updateUser(@PathVariable Long id, @Valid @RequestBody UpdateUserRequest updateUserRequest) {
        ApiResponse<?> response = userService.updateUser(id, updateUserRequest);
        
        if (response.isSuccess()) {
            // 清除用户相关的Redis缓存
            clearUserCache(id);
            logger.info("用户信息更新成功，已清除Redis缓存: userId={}", id);
        }
        
        return response;
    }

    /**
     * 删除用户（仅管理员）
     * 删除后清除Redis缓存
     */
    @DeleteMapping("/{id}")
    @PreAuthorize("hasRole('ADMIN')")
    public ApiResponse<?> deleteUser(@PathVariable Long id) {
        ApiResponse<?> response = userService.deleteUser(id);
        
        if (response.isSuccess()) {
            // 清除用户相关的Redis缓存
            clearUserCache(id);
            logger.info("用户删除成功，已清除Redis缓存: userId={}", id);
        }
        
        return response;
    }

    /**
     * 更新用户角色（仅管理员）
     * 更新后清除Redis缓存
     */
    @PutMapping("/{id}/roles")
    @PreAuthorize("hasRole('ADMIN')")
    public ApiResponse<?> updateUserRoles(@PathVariable Long id, @Valid @RequestBody UpdateRoleRequest request) {
        ApiResponse<?> response = userService.updateUserRoles(id, request.getRoles());
        
        if (response.isSuccess()) {
            // 清除用户相关的Redis缓存
            clearUserCache(id);
            logger.info("用户角色更新成功，已清除Redis缓存: userId={}", id);
        }
        
        return response;
    }

    /**
     * 更改用户密码（仅管理员或用户自己）
     * 修改后清除Redis缓存（虽然密码不缓存，但需保证缓存一致性）
     */
    @PutMapping("/{id}/password")
    @PreAuthorize("hasRole('ADMIN') or authentication.principal.id == #id")
    public ApiResponse<?> changePassword(@PathVariable Long id, @Valid @RequestBody ChangePasswordRequest changePasswordRequest) {
        ApiResponse<?> response = userService.changePassword(id, changePasswordRequest);
        
        if (response.isSuccess()) {
            // 清除用户相关的Redis缓存
            clearUserCache(id);
            logger.info("用户密码修改成功，已清除Redis缓存: userId={}", id);
        }
        
        return response;
    }

    /**
     * 更新用户头像
     * 更新后清除Redis缓存
     */
    @PutMapping("/{id}/avatar")
    @PreAuthorize("authentication.principal.id == #id or hasRole('ADMIN')")
    public ApiResponse<?> updateAvatar(@PathVariable Long id, @RequestParam String avatarUrl) {
        ApiResponse<?> response = userService.updateAvatar(id, avatarUrl);
        
        if (response.isSuccess()) {
            // 清除用户相关的Redis缓存
            clearUserCache(id);
            logger.info("用户头像更新成功，已清除Redis缓存: userId={}", id);
        }
        
        return response;
    }

    /**
     * 批量更新用户角色
     * 更新后批量清除Redis缓存
     */
    @PutMapping("/batch-roles")
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<?> updateBatchUserRoles(@Valid @RequestBody BatchUpdateRoleRequest batchUpdateRoleRequest) {
        try {
            userService.updateBatchUserRoles(batchUpdateRoleRequest.getUserIds(), batchUpdateRoleRequest.getRoles());
            
            // 批量清除用户缓存
            clearUserCacheBatch(batchUpdateRoleRequest.getUserIds());
            logger.info("批量更新用户角色成功，已清除Redis缓存: userIds={}", batchUpdateRoleRequest.getUserIds());
            
            return ResponseEntity.ok().body(new MessageResponse("批量更新用户角色成功"));
        } catch (IllegalArgumentException ex) {
            return ResponseEntity.badRequest().body(new MessageResponse(ex.getMessage()));
        } catch (Exception ex) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(new MessageResponse("批量更新用户角色失败：" + ex.getMessage()));
        }
    }
    
    /**
     * 批量注册用户
     */
    @PostMapping("/batch-register")
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<?> registerBatchUsers(@Valid @RequestBody BatchRegisterRequest batchRegisterRequest) {
        try {
            userService.registerBatchUsers(batchRegisterRequest.getUsers());
            return ResponseEntity.ok().body(new MessageResponse("批量注册用户成功"));
        } catch (IllegalArgumentException ex) {
            return ResponseEntity.badRequest().body(new MessageResponse(ex.getMessage()));
        } catch (Exception ex) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(new MessageResponse("批量注册用户失败：" + ex.getMessage()));
        }
    }

    /**
     * 封禁用户（仅管理员）
     * 封禁后清除Redis缓存
     */
    @PutMapping("/{id}/ban")
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<?> banUser(@PathVariable Long id) {
        ApiResponse<?> response = userService.banUser(id);
        
        if (response.isSuccess()) {
            // 清除用户相关的Redis缓存
            clearUserCache(id);
            logger.info("用户封禁成功，已清除Redis缓存: userId={}", id);
        }
        
        return ResponseEntity.ok(response);
    }

    /**
     * 解封用户（仅管理员）
     * 解封后清除Redis缓存
     */
    @PutMapping("/{id}/unban")
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<?> unbanUser(@PathVariable Long id) {
        ApiResponse<?> response = userService.unbanUser(id);
        
        if (response.isSuccess()) {
            // 清除用户相关的Redis缓存
            clearUserCache(id);
            logger.info("用户解封成功，已清除Redis缓存: userId={}", id);
        }
        
        return ResponseEntity.ok(response);
    }

    /**
     * 批量封禁用户（仅管理员）
     * 封禁后批量清除Redis缓存
     */
    @PutMapping("/batch-ban")
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<?> batchBanUsers(@RequestBody List<Long> userIds) {
        ApiResponse<?> response = userService.batchBanUsers(userIds);
        
        if (response.isSuccess()) {
            // 批量清除用户缓存
            clearUserCacheBatch(userIds);
            logger.info("批量封禁用户成功，已清除Redis缓存: userIds={}", userIds);
        }
        
        return ResponseEntity.ok(response);
    }

    /**
     * 批量解封用户（仅管理员）
     * 解封后批量清除Redis缓存
     */
    @PutMapping("/batch-unban")
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<?> batchUnbanUsers(@RequestBody List<Long> userIds) {
        ApiResponse<?> response = userService.batchUnbanUsers(userIds);
        
        if (response.isSuccess()) {
            // 批量清除用户缓存
            clearUserCacheBatch(userIds);
            logger.info("批量解封用户成功，已清除Redis缓存: userIds={}", userIds);
        }
        
        return ResponseEntity.ok(response);
    }

    // ==================== Redis缓存辅助方法 ====================
    
    /**
     * 从Redis缓存获取用户DTO信息
     * @param userId 用户ID
     * @return 缓存的用户DTO，如果不存在返回null
     */
    private UserDTO getCachedUserById(Long userId) {
        try {
            String userDTOCacheKey = "user:dto:" + userId;
            Object cachedUserObj = redisTemplate.opsForValue().get(userDTOCacheKey);
            
            if (cachedUserObj != null) {
                return objectMapper.readValue(cachedUserObj.toString(), UserDTO.class);
            }
        } catch (Exception e) {
            logger.warn("从Redis获取用户DTO失败: userId={}, error={}", userId, e.getMessage());
        }
        return null;
    }
    
    /**
     * 缓存用户DTO信息到Redis
     * @param userDTO 用户DTO对象
     */
    private void cacheUserDTO(UserDTO userDTO) {
        try {
            String userDTOCacheKey = "user:dto:" + userDTO.getId();
            String userDTOJson = objectMapper.writeValueAsString(userDTO);
            
            // 缓存30分钟
            redisTemplate.opsForValue().set(userDTOCacheKey, userDTOJson, 30, TimeUnit.MINUTES);
            
        } catch (Exception e) {
            logger.warn("缓存用户DTO到Redis失败: userId={}, error={}", userDTO.getId(), e.getMessage());
        }
    }
    
    /**
     * 清除指定用户的所有Redis缓存
     * @param userId 用户ID
     */
    private void clearUserCache(Long userId) {
        try {
            // 获取用户信息以便清除username相关的缓存
            User user = userService.getUserById(userId);
            if (user != null) {
                // 清除基本用户信息缓存
                String userBasicCacheKey = "user:basic:" + user.getUsername();
                redisTemplate.delete(userBasicCacheKey);
                
                // 清除用户DTO缓存
                String userDTOCacheKey = "user:dto:" + userId;
                redisTemplate.delete(userDTOCacheKey);
                
                logger.debug("已清除用户Redis缓存: userId={}, username={}", userId, user.getUsername());
            }
        } catch (Exception e) {
            logger.warn("清除用户Redis缓存失败: userId={}, error={}", userId, e.getMessage());
        }
    }
    
    /**
     * 批量清除用户Redis缓存
     * @param userIds 用户ID列表
     */
    private void clearUserCacheBatch(List<Long> userIds) {
        try {
            for (Long userId : userIds) {
                clearUserCache(userId);
            }
        } catch (Exception e) {
            logger.warn("批量清除用户Redis缓存失败: userIds={}, error={}", userIds, e.getMessage());
        }
    }
}